#include "connectiondialog.h"
#include <QFormLayout>
#include <QSqlDatabase>
#include <QFileDialog>
#include <QSettings>
#include <QJsonDocument>
#include <QJsonObject>
#include <QMessageBox>

ConnectionDialog::ConnectionDialog(QWidget *parent)
    : DDialog(parent)
{
    setupUI();
    initDrivers();
    loadSettings();
}

void ConnectionDialog::setupUI()
{
    setTitle(tr("Database Connection"));
    setIcon(QIcon::fromTheme("database"));

    auto mainWidget = new QWidget(this);
    auto layout = new QVBoxLayout(mainWidget);

    // Create tab widget
    auto tabWidget = new DTabWidget(this);
    setupBasicTab(tabWidget);
    setupSSLTab(tabWidget);
    setupAdvancedTab(tabWidget);
    
    layout->addWidget(tabWidget);
    
    // Add template buttons
    auto templateLayout = new QHBoxLayout;
    saveTemplateBtn = new DPushButton(tr("Save as Template"), this);
    loadTemplateBtn = new DPushButton(tr("Load Template"), this);
    templateLayout->addWidget(saveTemplateBtn);
    templateLayout->addWidget(loadTemplateBtn);
    layout->addLayout(templateLayout);
    
    // Add test connection button
    auto testBtn = new DPushButton(tr("Test Connection"), this);
    layout->addWidget(testBtn);
    
    addContent(mainWidget);
    addButton(tr("OK"), true, DDialog::ButtonRecommend);
    addButton(tr("Cancel"), false, DDialog::ButtonNormal);
    
    // Connect signals
    connect(driverCombo, &DComboBox::currentTextChanged,
            this, &ConnectionDialog::updateDefaultPort);
    connect(useSSLCheck, &DCheckBox::toggled,
            this, &ConnectionDialog::updateSSLControls);
    connect(browseCertBtn, &DPushButton::clicked,
            this, &ConnectionDialog::browseSSLCert);
    connect(browseKeyBtn, &DPushButton::clicked,
            this, &ConnectionDialog::browseSSLKey);
    connect(browseCABtn, &DPushButton::clicked,
            this, &ConnectionDialog::browseSSLCA);
    connect(browseDbBtn, &DPushButton::clicked,
            this, &ConnectionDialog::browseDatabase);
    connect(testBtn, &DPushButton::clicked,
            this, &ConnectionDialog::testConnection);
    connect(saveTemplateBtn, &DPushButton::clicked,
            this, &ConnectionDialog::saveAsTemplate);
    connect(loadTemplateBtn, &DPushButton::clicked,
            this, &ConnectionDialog::loadTemplate);
}

void ConnectionDialog::setupBasicTab(DTabWidget *tabWidget)
{
    auto widget = new QWidget(this);
    auto layout = new QFormLayout(widget);

    nameEdit = new DLineEdit(this);
    driverCombo = new DComboBox(this);
    hostEdit = new DLineEdit(this);
    portSpin = new DSpinBox(this);
    dbNameEdit = new DLineEdit(this);
    browseDbBtn = new DPushButton(tr("Browse"), this);
    userEdit = new DLineEdit(this);
    passwordEdit = new DLineEdit(this);
    
    portSpin->setRange(1, 65535);
    passwordEdit->setEchoMode(QLineEdit::Password);
    
    // Add database browse button for SQLite
    auto dbLayout = new QHBoxLayout;
    dbLayout->addWidget(dbNameEdit);
    dbLayout->addWidget(browseDbBtn);
    
    layout->addRow(tr("Connection Name:"), nameEdit);
    layout->addRow(tr("Database Type:"), driverCombo);
    layout->addRow(tr("Host:"), hostEdit);
    layout->addRow(tr("Port:"), portSpin);
    layout->addRow(tr("Database:"), dbLayout);
    layout->addRow(tr("Username:"), userEdit);
    layout->addRow(tr("Password:"), passwordEdit);
    
    tabWidget->addTab(widget, tr("Basic"));
}

void ConnectionDialog::setupSSLTab(DTabWidget *tabWidget)
{
    auto widget = new QWidget(this);
    auto layout = new QFormLayout(widget);

    useSSLCheck = new DCheckBox(tr("Use SSL/TLS"), this);
    sslCertEdit = new DLineEdit(this);
    sslKeyEdit = new DLineEdit(this);
    sslCAEdit = new DLineEdit(this);
    browseCertBtn = new DPushButton(tr("Browse"), this);
    browseKeyBtn = new DPushButton(tr("Browse"), this);
    browseCABtn = new DPushButton(tr("Browse"), this);
    
    auto certLayout = new QHBoxLayout;
    certLayout->addWidget(sslCertEdit);
    certLayout->addWidget(browseCertBtn);
    
    auto keyLayout = new QHBoxLayout;
    keyLayout->addWidget(sslKeyEdit);
    keyLayout->addWidget(browseKeyBtn);
    
    auto caLayout = new QHBoxLayout;
    caLayout->addWidget(sslCAEdit);
    caLayout->addWidget(browseCABtn);
    
    layout->addRow(useSSLCheck);
    layout->addRow(tr("Client Certificate:"), certLayout);
    layout->addRow(tr("Client Key:"), keyLayout);
    layout->addRow(tr("CA Certificate:"), caLayout);
    
    tabWidget->addTab(widget, tr("SSL/TLS"));
    
    // Initially disable SSL controls
    updateSSLControls();
}

void ConnectionDialog::setupAdvancedTab(DTabWidget *tabWidget)
{
    auto widget = new QWidget(this);
    auto layout = new QFormLayout(widget);

    timeoutSpin = new DSpinBox(this);
    charsetCombo = new DComboBox(this);
    autoReconnectCheck = new DCheckBox(tr("Auto Reconnect"), this);
    compressCheck = new DCheckBox(tr("Compress Protocol"), this);
    
    timeoutSpin->setRange(1, 3600);
    timeoutSpin->setValue(30);
    timeoutSpin->setSuffix(tr(" seconds"));
    
    // Add common charsets
    charsetCombo->addItems({"utf8mb4", "utf8", "latin1", "ascii"});
    
    layout->addRow(tr("Connection Timeout:"), timeoutSpin);
    layout->addRow(tr("Character Set:"), charsetCombo);
    layout->addRow(autoReconnectCheck);
    layout->addRow(compressCheck);
    
    tabWidget->addTab(widget, tr("Advanced"));
}

void ConnectionDialog::initDrivers()
{
    // 获取可用的数据库驱动
    auto drivers = QSqlDatabase::drivers();
    
    // 过滤出常用数据库驱动
    QStringList commonDrivers;
    if (drivers.contains("QMYSQL"))
        commonDrivers << "MySQL";
    if (drivers.contains("QPSQL"))
        commonDrivers << "PostgreSQL";
    if (drivers.contains("QSQLITE"))
        commonDrivers << "SQLite";
    if (drivers.contains("QODBC"))
        commonDrivers << "ODBC";
    if (drivers.contains("QMONGODB"))
        commonDrivers << "MongoDB";
    if (drivers.contains("QOCI"))
        commonDrivers << "Oracle";
    
    driverCombo->addItems(commonDrivers);
}

void ConnectionDialog::updateDefaultPort(const QString &driver)
{
    // 设置默认端口
    if (driver == "MySQL")
        portSpin->setValue(3306);
    else if (driver == "PostgreSQL")
        portSpin->setValue(5432);
    else if (driver == "MongoDB")
        portSpin->setValue(27017);
    else if (driver == "Oracle")
        portSpin->setValue(1521);
    else
        portSpin->setValue(0);
        
    // Update UI based on driver
    bool isSQLite = (driver == "SQLite");
    hostEdit->setEnabled(!isSQLite);
    portSpin->setEnabled(!isSQLite);
    browseDbBtn->setVisible(isSQLite);
}

void ConnectionDialog::updateSSLControls()
{
    bool enabled = useSSLCheck->isChecked();
    sslCertEdit->setEnabled(enabled);
    sslKeyEdit->setEnabled(enabled);
    sslCAEdit->setEnabled(enabled);
    browseCertBtn->setEnabled(enabled);
    browseKeyBtn->setEnabled(enabled);
    browseCABtn->setEnabled(enabled);
}

void ConnectionDialog::browseSSLCert()
{
    QString file = QFileDialog::getOpenFileName(this,
        tr("Select Client Certificate"), QString(),
        tr("Certificate Files (*.pem *.crt);;All Files (*)"));
    if (!file.isEmpty())
        sslCertEdit->setText(file);
}

void ConnectionDialog::browseSSLKey()
{
    QString file = QFileDialog::getOpenFileName(this,
        tr("Select Client Key"), QString(),
        tr("Key Files (*.pem *.key);;All Files (*)"));
    if (!file.isEmpty())
        sslKeyEdit->setText(file);
}

void ConnectionDialog::browseSSLCA()
{
    QString file = QFileDialog::getOpenFileName(this,
        tr("Select CA Certificate"), QString(),
        tr("Certificate Files (*.pem *.crt);;All Files (*)"));
    if (!file.isEmpty())
        sslCAEdit->setText(file);
}

void ConnectionDialog::browseDatabase()
{
    QString file = QFileDialog::getOpenFileName(this,
        tr("Select Database File"), QString(),
        tr("SQLite Database (*.db *.sqlite);;All Files (*)"));
    if (!file.isEmpty())
        dbNameEdit->setText(file);
}

void ConnectionDialog::testConnection()
{
    // Create a temporary database connection
    QSqlDatabase db = QSqlDatabase::addDatabase(driverName(), "test_connection");
    db.setHostName(hostName());
    db.setPort(port());
    db.setDatabaseName(databaseName());
    db.setUserName(userName());
    db.setPassword(password());
    
    // Set SSL options if enabled
    if (useSSL()) {
        db.setConnectOption("SSL", true);
        db.setConnectOption("SSLCert", sslCert());
        db.setConnectOption("SSLKey", sslKey());
        db.setConnectOption("SSLCA", sslCA());
    }
    
    // Set advanced options
    db.setConnectOption("ConnectTimeout", connectTimeout());
    db.setConnectOption("CharacterSet", charset());
    db.setConnectOption("AutoReconnect", autoReconnect());
    db.setConnectOption("Compress", compressProtocol());
    
    // Try to connect
    if (db.open()) {
        DMessageBox::information(this, tr("Success"),
            tr("Connection test successful!"));
        db.close();
    } else {
        DMessageBox::warning(this, tr("Error"),
            tr("Connection failed: %1").arg(db.lastError().text()));
    }
    
    // Remove test connection
    QSqlDatabase::removeDatabase("test_connection");
}

void ConnectionDialog::saveAsTemplate()
{
    QString name = DInputDialog::getText(this, tr("Save Template"),
        tr("Template Name:"));
    if (name.isEmpty())
        return;
        
    QJsonObject json;
    json["driver"] = driverCombo->currentText();
    json["host"] = hostEdit->text();
    json["port"] = portSpin->value();
    json["database"] = dbNameEdit->text();
    json["username"] = userEdit->text();
    
    // SSL settings
    json["useSSL"] = useSSLCheck->isChecked();
    json["sslCert"] = sslCertEdit->text();
    json["sslKey"] = sslKeyEdit->text();
    json["sslCA"] = sslCAEdit->text();
    
    // Advanced settings
    json["timeout"] = timeoutSpin->value();
    json["charset"] = charsetCombo->currentText();
    json["autoReconnect"] = autoReconnectCheck->isChecked();
    json["compress"] = compressCheck->isChecked();
    
    QSettings settings;
    settings.beginGroup("ConnectionTemplates");
    settings.setValue(name, QJsonDocument(json).toJson(QJsonDocument::Compact));
    settings.endGroup();
}

void ConnectionDialog::loadTemplate()
{
    QSettings settings;
    settings.beginGroup("ConnectionTemplates");
    QStringList templates = settings.childKeys();
    settings.endGroup();
    
    if (templates.isEmpty()) {
        DMessageBox::information(this, tr("No Templates"),
            tr("No connection templates found."));
        return;
    }
    
    QString name = DInputDialog::getItem(this, tr("Load Template"),
        tr("Select Template:"), templates);
    if (name.isEmpty())
        return;
        
    settings.beginGroup("ConnectionTemplates");
    QJsonObject json = QJsonDocument::fromJson(
        settings.value(name).toByteArray()).object();
    settings.endGroup();
    
    driverCombo->setCurrentText(json["driver"].toString());
    hostEdit->setText(json["host"].toString());
    portSpin->setValue(json["port"].toInt());
    dbNameEdit->setText(json["database"].toString());
    userEdit->setText(json["username"].toString());
    
    // SSL settings
    useSSLCheck->setChecked(json["useSSL"].toBool());
    sslCertEdit->setText(json["sslCert"].toString());
    sslKeyEdit->setText(json["sslKey"].toString());
    sslCAEdit->setText(json["sslCA"].toString());
    
    // Advanced settings
    timeoutSpin->setValue(json["timeout"].toInt());
    charsetCombo->setCurrentText(json["charset"].toString());
    autoReconnectCheck->setChecked(json["autoReconnect"].toBool());
    compressCheck->setChecked(json["compress"].toBool());
}

void ConnectionDialog::loadSettings()
{
    QSettings settings;
    settings.beginGroup("ConnectionDialog");
    
    // Load last used values
    driverCombo->setCurrentText(settings.value("lastDriver").toString());
    hostEdit->setText(settings.value("lastHost").toString());
    portSpin->setValue(settings.value("lastPort", 3306).toInt());
    userEdit->setText(settings.value("lastUser").toString());
    charsetCombo->setCurrentText(settings.value("lastCharset", "utf8mb4").toString());
    
    settings.endGroup();
}

void ConnectionDialog::saveSettings()
{
    QSettings settings;
    settings.beginGroup("ConnectionDialog");
    
    // Save last used values
    settings.setValue("lastDriver", driverCombo->currentText());
    settings.setValue("lastHost", hostEdit->text());
    settings.setValue("lastPort", portSpin->value());
    settings.setValue("lastUser", userEdit->text());
    settings.setValue("lastCharset", charsetCombo->currentText());
    
    settings.endGroup();
}

// Getter methods implementation...
QString ConnectionDialog::connectionName() const
{
    return nameEdit->text();
}

QString ConnectionDialog::driverName() const
{
    QString driver = driverCombo->currentText();
    if (driver == "MySQL")
        return "QMYSQL";
    else if (driver == "PostgreSQL")
        return "QPSQL";
    else if (driver == "SQLite")
        return "QSQLITE";
    else if (driver == "ODBC")
        return "QODBC";
    else if (driver == "MongoDB")
        return "QMONGODB";
    else if (driver == "Oracle")
        return "QOCI";
    return QString();
}

// ... other getter methods ...

void ConnectionDialog::setConnection(const QString &name, const QSqlDatabase &db)
{
    nameEdit->setText(name);
    
    // Set driver type
    QString driver = db.driverName();
    if (driver == "QMYSQL")
        driverCombo->setCurrentText("MySQL");
    else if (driver == "QPSQL")
        driverCombo->setCurrentText("PostgreSQL");
    else if (driver == "QSQLITE")
        driverCombo->setCurrentText("SQLite");
    else if (driver == "QODBC")
        driverCombo->setCurrentText("ODBC");
    else if (driver == "QMONGODB")
        driverCombo->setCurrentText("MongoDB");
    else if (driver == "QOCI")
        driverCombo->setCurrentText("Oracle");
        
    hostEdit->setText(db.hostName());
    portSpin->setValue(db.port());
    dbNameEdit->setText(db.databaseName());
    userEdit->setText(db.userName());
    passwordEdit->setText(db.password());
    
    // Set SSL options
    QVariant sslOption = db.connectOptions()["SSL"];
    useSSLCheck->setChecked(sslOption.toBool());
    if (sslOption.toBool()) {
        sslCertEdit->setText(db.connectOptions()["SSLCert"].toString());
        sslKeyEdit->setText(db.connectOptions()["SSLKey"].toString());
        sslCAEdit->setText(db.connectOptions()["SSLCA"].toString());
    }
    
    // Set advanced options
    timeoutSpin->setValue(db.connectOptions()["ConnectTimeout"].toInt());
    charsetCombo->setCurrentText(db.connectOptions()["CharacterSet"].toString());
    autoReconnectCheck->setChecked(db.connectOptions()["AutoReconnect"].toBool());
    compressCheck->setChecked(db.connectOptions()["Compress"].toBool());
}